﻿using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using HandyControl.Controls;
using HandyControl.Data;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Threading;

namespace 串口通信Demo.Wpf
{
    public partial class MainWindowViewModel : ObservableObject
    {
        public ObservableCollection<ComboBoxDataInfo<string, string>> ComPortList { get; set; } = new();
        public ObservableCollection<ComboBoxDataInfo<string, string>> BaudRateList { get; set; } = new();
        public ObservableCollection<ComboBoxDataInfo<string, string>> DataBitsList { get; set; } = new();
        public ObservableCollection<ComboBoxDataInfo<string, string>> StopBitsList { get; set; } = new();
        public ObservableCollection<ComboBoxDataInfo<string, string>> ParityList { get; set; } = new();

        [ObservableProperty]
        private string comPort;

        [ObservableProperty]
        private string baudRate;

        [ObservableProperty]
        private string dataBits;

        [ObservableProperty]
        private string stopBits;

        [ObservableProperty]
        private string parity;

        [ObservableProperty]
        private bool connectStatus;

        [ObservableProperty]
        private string openText;

        [ObservableProperty]
        private bool isDtr;

        [ObservableProperty]
        private bool isRts;

        [ObservableProperty]
        private string receiveInfo;

        [ObservableProperty]
        private string sendInfo=string.Empty;

        private bool IsHexSend;

        private bool IsAutoSend;

        private SerialPort serialPort = new();

        public MainWindowViewModel()
        {
            Init();
        }

        private void Init()
        {
            //端口号
            string[] portList = SerialPort.GetPortNames();
            if (portList.Length > 0)
            {
                portList.ToList().ForEach(p => ComPortList.Add(new ComboBoxDataInfo<string, string>() { Value = p, Display = p }));
            }
            ComPort = ComPortList.First().Value;

            //波特率
            BaudRateList.Add(new ComboBoxDataInfo<string, string>() { Value = "9600", Display = "9600" });
            BaudRateList.Add(new ComboBoxDataInfo<string, string>() { Value = "19200", Display = "19200" });
            BaudRateList.Add(new ComboBoxDataInfo<string, string>() { Value = "38400", Display = "38400" });
            BaudRateList.Add(new ComboBoxDataInfo<string, string>() { Value = "57600", Display = "57600" });
            BaudRateList.Add(new ComboBoxDataInfo<string, string>() { Value = "115200", Display = "115200" });
            BaudRate = BaudRateList.First().Value;

            //数据位
            DataBitsList.Add(new ComboBoxDataInfo<string, string>() { Value = "7", Display = "7" });
            DataBitsList.Add(new ComboBoxDataInfo<string, string>() { Value = "8", Display = "8" });
            DataBits = DataBitsList.First().Value;

            //校验位
            Enum.GetNames(typeof(Parity)).ToList().ForEach(p => ParityList.Add(new ComboBoxDataInfo<string, string>() { Value = p, Display = p }));
            Parity = ParityList.First().Value;

            //停止位
            Enum.GetNames(typeof(StopBits)).ToList().ForEach(p => StopBitsList.Add(new ComboBoxDataInfo<string, string>() { Value = p, Display = p }));
            StopBits = StopBitsList[1].Value;

            ConnectStatus = false;

            OpenText = "打开串口";

            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

            Task.Run(()=>AutoSend());
        }

        private async void AutoSend()
        {
            while (true)
            {
                if (IsAutoSend)
                {
                    SendData();
                }
                await Task.Delay(1000);
            }
        }

        [RelayCommand]
        private void IsDtrChecked()
        {
            this.serialPort.DtrEnable = true;
        }

        [RelayCommand]
        private void IsDtrUnChecked()
        {
            this.serialPort.DtrEnable = false;
        }

        [RelayCommand]
        private void IsRtsChecked()
        {
            this.serialPort.RtsEnable = true;
        }

        [RelayCommand]
        private void IsRtsUnChecked()
        {
            this.serialPort.RtsEnable = false;
        }

        [RelayCommand]
        private void IsHexSendChecked()
        {
            IsHexSend = true;
        }

        [RelayCommand]
        private void IsHexSendUnChecked()
        {
            IsHexSend = false;
        }

        [RelayCommand]
        private void IsAutoSendChecked()
        {
            IsAutoSend = true;
        }

        [RelayCommand]
        private void IsAutoSendUnChecked()
        {
            IsAutoSend = false;
        }

        [RelayCommand]
        private void Open()
        {
            if (OpenText == "打开串口")
            {
                serialPort.PortName = ComPort;
                serialPort.BaudRate = int.Parse(BaudRate);
                serialPort.DataBits = int.Parse(DataBits);
                serialPort.Parity = (Parity)Enum.Parse(typeof(Parity), Parity);
                serialPort.StopBits = (StopBits)Enum.Parse(typeof(StopBits), StopBits);
                serialPort.RtsEnable = IsRts;
                serialPort.DtrEnable = IsDtr;
                serialPort.Encoding = System.Text.Encoding.GetEncoding("GB2312");
                
                if (!serialPort.IsOpen)
                {
                    try
                    {
                        serialPort.Open();
                        serialPort.DataReceived += SerialPort_DataReceived;
                        ConnectStatus = true;
                        Growl.Success("串口已打开！");
                        OpenText = "关闭串口";
                    }
                    catch (Exception ex)
                    {
                        Growl.Warning("打开串口失败！" + ex.Message);
                        return;
                    }
                }
                else
                {
                    Growl.Warning("串口已经打开！");
                    ConnectStatus = false;
                }
            }
            else
            {
                if (serialPort.IsOpen)
                {
                    this.serialPort.Close();
                    OpenText = "打开串口";
                    ConnectStatus = false;
                    Growl.Success("串口已关闭！");
                }
            }
        }

        [RelayCommand]
        private void Send()
        {
            SendData();
        }

        private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            if (IsHexSend)
            {
                //定义一个字节数组
                try
                {
                    //定义最终的字符串
                    string revStr = string.Empty;
                    //它告诉你当前有多少字节的数据已经在缓冲区中等待被读取
                    byte[] data = new byte[serialPort.BytesToRead];

                    //读取缓冲区值到字节数组
                    this.serialPort.Read(data, 0, data.Length);

                    //拼接显示
                    foreach (byte item in data)
                    {
                        string hex = Convert.ToString(item, 16).ToUpper();

                        revStr += (hex.Length == 1 ? "0" + hex : hex) + " ";
                    }

                    Dispatcher.CurrentDispatcher.Invoke(new Action(() =>
                    {
                        ReceiveInfo += revStr + Environment.NewLine;
                    }));
                }
                catch (Exception ex)
                {
                    Dispatcher.CurrentDispatcher.Invoke(new Action(() =>
                    {
                        ReceiveInfo += ("接收出现错误：" + ex.Message + Environment.NewLine);
                    }));
                }
            }
            else
            {
                //用于读取串口接收缓冲区中的所有立即可用数据，并将其作为字符串返回
                string revStr = serialPort.ReadExisting();
                Dispatcher.CurrentDispatcher.Invoke(new Action(() =>
                {
                    ReceiveInfo += ("接收到数据：" + revStr + Environment.NewLine);
                }));
            }
        }

        private void SendData()
        {
            if (serialPort.IsOpen)
            {
                string sendData = SendInfo.Replace(" ", "");

                if (sendData == string.Empty)
                {
                    Growl.Warning("请输入要发送的数据！");
                    return;
                }
                if (IsHexSend)
                {
                    try
                    {
                        //两个十六进制字符代表一个字节
                        byte[] sendBytes = new byte[sendData.Length / 2];
                        for (int i = 0; i < sendData.Length / 2; i++)
                        {
                            sendBytes[i] = Convert.ToByte(sendData.Substring(i * 2, 2), 16);
                        }
                        serialPort.Write(sendBytes, 0, sendBytes.Length);
                    }
                    catch (Exception)
                    {
                        Growl.Warning(" 16进制格式不对");
                        return;
                    }
                   
                }
                else
                {
                    byte[] sendBytes = Encoding.GetEncoding("GB2312").GetBytes(sendData);
                    serialPort.Write(sendBytes, 0, sendBytes.Length);
                
                }
                Growl.Success("已发送：" + sendData);
            }
            else
            {
                Growl.Warning("请先打开串口！");
            }
        }
    }

    public class ComboBoxDataInfo<Tkey, TValue>
    {
        public Tkey Value { get; set; }
        public TValue Display { get; set; }
    }
}